#include <functional>
#include <sstream>

#include "engine.h"
#include "baseCTF.h"
#include "clientbackend.h"
#include "states.h"
#include "statechanges.h"

//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//  some very basic examples implementing the above interfaces (not intended for actual use)

using namespace std;
/*
class MapState : public State
{
public:
	// dimensions of 2D square grid
	int w, h;
	// terrain type of each grid square
	vector<int> terrain;
	// visibility of each grid square: which players have seen it
	vector<PlayerMask> visibility;

	virtual void censor(const PlayerMask& mask)
	{
		for (int i = 0; i < w*h; i++)
		{
			visibility[i] &= mask;
			if (visibility[i] == UNKNOWN)
				terrain[i] = 0;
		}
		// note that the w and h are never censored; everyone always knows those
	}

	virtual string getPrefix() const {return "#Map";}

	virtual string serialize() const
	{
		ostringstream ostr;
		ostr << getPrefix() << " " << w << " " << h;
		for (int i = 0; i < w*h; i++)
			ostr << " " << terrain[i] << " " << visibility[i];
		return ostr.str();
	}

	virtual string serialize(const PlayerMask& mask) const
	{
		MapState playercopy(*this);
		playercopy.censor(mask);
		return playercopy.serialize();
	}

	virtual bool unserialize(const string& str);
};

class CamperState : public State
{
public:
	// position on map
	int x, y;
	PlayerMask positionMask;

	virtual void censor(const PlayerMask& mask)
	{
		positionMask &= mask;
		if (positionMask == UNKNOWN)
		{
			x = 0;
			y = 0;
		}
	}

	virtual string getPrefix() const {return "#Camper";}

	virtual string serialize() const
	{
		ostringstream ostr;
		ostr << getPrefix() << " " << x << " " << y << " " << positionMask;
		return ostr.str();
	}

	virtual string serialize(const PlayerMask& mask) const
	{
		CamperState playercopy(*this);
		playercopy.censor(mask);
		return playercopy.serialize();
	}

	virtual bool unserialize(const string& str);
};

class CamperMove : public StateChange
{
private:
	// a camper moves from one position, where he can be seen by some subset of
	//  players (including his owner, naturally), to another position, where he
	//  can be seen by some other subset of players
	int playerID, camperID;  // invalid if both masks are UNKNOWN
	int oldx, oldy, newx, newy;
	PlayerMask oldmask, newmask;

	// provided by the Game object on initialization: a function that obtains
	//  the CamperState to modify, given the player and camper ID
	function<CamperState& (int, int)> camperLookup;

public:
	CamperMove(function<CamperState& (int, int)> camperLookup) : camperLookup(camperLookup) {}

	virtual void apply()
	{
		CamperState& camper = camperLookup(playerID, camperID);
		camper.x = newx;
		camper.y = newy;
		camper.positionMask = newmask;
	}

	virtual void undo()
	{
		CamperState& camper = camperLookup(playerID, camperID);
		camper.x = oldx;
		camper.y = oldy;
		camper.positionMask = oldmask;
	}

	virtual void censor(const PlayerMask& mask)
	{
		oldmask &= mask;
		if (oldmask == UNKNOWN)
		{
			oldx = 0;
			oldy = 0;
		}
		newmask &= mask;
		if (newmask == UNKNOWN)
		{
			newx = 0;
			newy = 0;
		}
		if (oldmask == UNKNOWN && newmask == UNKNOWN)
		{
			playerID = -1;
			camperID = -1;
		}
	}

	virtual string getPrefix() const {return "$CamperMove";}

	virtual string serialize() const;
	virtual string serialize(const PlayerMask& mask) const;
	virtual bool unserialize(const string& str);
};

class VisibilityChange : public StateChange
{
private:
	// This represents a set of tiles becoming visible to a single player.
	// Note that although the terrain values never change on the server,
	//  they have to be included in this StateChange because the client does
	//  not know them until the tiles become visible.
	PlayerMask visMask;
	vector<int> tiles;  // indices of the changed tiles
	vector<int> terrain;  // terrain values of the changed tiles

	function<MapState& ()> mapLookup;

public:
	VisibilityChange(function<MapState& ()> mapLookup) : mapLookup(mapLookup) {}

	virtual void apply()
	{
		MapState& map = mapLookup();
		for (vector<int>::size_type i = 0; i < tiles.size(); i++)
		{
			map.terrain[tiles[i]] = terrain[i];  // on the server, this has no effect
			map.visibility[tiles[i]] |= visMask;
		}
	}

	virtual void undo()
	{
		MapState& map = mapLookup();
		for (vector<int>::size_type i = 0; i < tiles.size(); i++)
			map.visibility[tiles[i]] &= ~visMask;
	}

	virtual void censor(const PlayerMask& mask)
	{
		// only the affected player gets to know what happened
		visMask &= mask;
		if (visMask == UNKNOWN)
		{
			tiles.clear();
			terrain.clear();
		}
	}

	virtual string getPrefix() const {return "$VisChange";}

	virtual string serialize() const;
	virtual string serialize(const PlayerMask& mask) const;
	virtual bool unserialize(const string& str);
};

string getPrefix(const string& msg);

class ExampleGame : public Game
{
private:
	MapState map;
	vector<vector<CamperState> > campers;  // indexed by player, then camper (yeah, this is stupid!)

public:
	CamperState& getCamper(int playerID, int camperID) {return campers[playerID][camperID];}
	MapState& getMap() {return map;}

	virtual std::vector<std::shared_ptr<StateChange> > validateAction(std::shared_ptr<Action> action) const
	{
		// if the action is a camper move, then make sure it's legal--make sure the described camper
		//  has movement points, the destination isn't too far, etc.

		// if it's legal, create a CamperMove describing the change, and, if necessary, a VisibilityChange
		//  with any tiles that are newly visible to the player as a result, and return those
	}

	virtual std::shared_ptr<StateChange> stateChangeFactory(const std::string& str)
	{
		shared_ptr<StateChange> change;
		if (str == "$CamperMove")
			change.reset(new CamperMove(bind(&ExampleGame::getCamper, this, placeholders::_1, placeholders::_2)));
		else if (str == "$VisChange")
			change.reset(new VisibilityChange(bind(&ExampleGame::getMap, this)));
		if (change && !change->unserialize(str))
			change.reset();
		return change;
	}

	virtual std::shared_ptr<Action> actionFactory(const std::string& str);
};
*/